#!/usr/bin/python

#
# Copyright 2008 Amit Shrestha
#

'''
This file is part of Words.

Words is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Words is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
'''

import sys
import random
from os import path

from javax.swing import DefaultListModel

from core.DB import DB
from gui.MainFrame import MainFrame
from gui.DictionaryFrame import DictionaryFrame

from listeners import KeyboardListener
from listeners import MenuListener
from listeners import MyMouseListener
from listeners import MyHyperlinkListener
from listeners import MyWindowListener

#
# settings
#
DB_FILEPATH_DEFAULT = 'files/db.txt'
INDEX_PATTERNS_FILEPATH_DEFAULT = 'files/patterns_to_index.txt'

class MainClass:
    def __init__(self):
        self.db = DB()
        self.number_of_choices = 5
        self.dframe = None

        db_path = DB_FILEPATH_DEFAULT
        index_patterns_path = INDEX_PATTERNS_FILEPATH_DEFAULT

        if path.exists(".db.txt"):
            print 'Loading previously saved DB...'
            db_path = ".db.txt"
        else:
            print 'Loading default DB...'
        
        if path.exists(".patterns_to_index.txt"):
            print "Loading customized index patterns..."
            index_patterns_path = ".patterns_to_index.txt"
        else:
            print 'Loading default index patterns...'
        
        self.db.read_db(db_path,index_patterns_path)
        print 'Done loading DB and index patterns.'

        index_names = self.db.get_available_index_names()
        index_names.sort()
        self.active_index_name = index_names[0]
        self.main_frame = MainFrame(index_names)
        
        self.__add_listeners()
        self.test()
        self.main_frame.panel_output.output_box.grabFocus()

    def __get_next_test_word(self):
        indices = self.db.get_indices(self.active_index_name)
        if len(indices) <= 0 :
            self.main_frame.panel_output.output_box.setText('<h3>You have mastered all the words in the current index!</h3><h3>Please choose a different index.</h3>')
            return (-1,None)
        rindex = random.randint(0,len(indices)-1)
        return (indices[rindex],self.db.words[indices[rindex]])

    def __get_trick_words(self, n):
        test_words = []
        while len(test_words) != n:
            rindex = random.randint(0,len(self.db.words)-1)
            if test_words.count(self.db.words[rindex]) == 0:
                test_words.append(self.db.words[rindex])
        return test_words

    def __add_listeners(self):
        self.keyboard_listener = KeyboardListener(self)
        self.hyperlink_listener = MyHyperlinkListener(self)
        self.mouse_listener = MyMouseListener(self)
        self.menu_listener = MenuListener(self,self.db.get_available_index_names())
        self.window_listener = MyWindowListener(self)
        
        self.main_frame.addWindowListener(self.window_listener)
        self.main_frame.panel_output.output_box.addKeyListener(self.keyboard_listener)
        self.main_frame.panel_output.output_box.addHyperlinkListener(self.hyperlink_listener)
        self.main_frame.panel_choices.choices_box.addKeyListener(self.keyboard_listener)
        self.main_frame.menu_bar.file_menu_practice_sets.addMouseListener(self.mouse_listener)
        for x in self.main_frame.menu_bar.menu_items:
            x.addActionListener(self.menu_listener)
   
    def get_word_html(self,word):
        output = '<b><u>%s</u></b>&nbsp;&nbsp;[ <a href="%s">Find definition in dict.org</a> ]<br/><br/>' % (word.name,word.name)
        if word.pronunciations:
            output += '<b>Pronunciation</b>&nbsp;&nbsp;&nbsp;%s <a href="pronunciation_guide">Help</a><br/>' % (",".join(word.pronunciations))
        output += '<b>Meanings</b>'
        output += '<br/><ol>'
        number_of_meanings = len(word.meanings)
        for i in range(number_of_meanings):
            number_of_examples = len(word.meanings[i][1])
            output += "<li>%s" % word.meanings[i][0]
            if(number_of_examples > 0): output += ". e.g. "
            for j in range(number_of_examples):
                output += "%s. " % word.meanings[i][1][j]
            output += "</li>"
        output += "</ol>"
        if word.synonyms:
            output += '<b>Synonyms</b><br/>&nbsp;&nbsp;%s<br/>' % (", ".join(['<a href="' + x + '">' + x + '</a>' for x in word.synonyms]))
        if word.antonyms:
            output += '<b>Antonyms</b><br/>&nbsp;&nbsp;%s' % (", ".join(['<a href="' + x + '">' + x + '</a>' for x in word.antonyms]))
        return output

    def get_statistics_html(self):
        number_of_words_tested = self.db.get_number_of_words_tested()
        number_of_words_mastered = self.db.get_number_of_words_mastered()
        
        if number_of_words_mastered > 4000: 
            grade = "A++"
        elif number_of_words_mastered > 3000:
            grade = "A!"
        elif number_of_words_mastered > 1500:
            grade = "B+!"
        elif number_of_words_mastered > 700:
            grade = "B!"
        elif number_of_words_mastered > 500:
            grade = "C"
        elif number_of_words_mastered > 300:
            grade = "D"
        else:
            grade = "Ungraded. You have to work more."

        html = "<html><body>"
        html += '<h3 bgcolor="rgb(200,200,200)">&nbsp;<b>Your Grade</b> : %s</h3>' % grade
        
        html += '<table width="100%">'
        html += "<tr><td>Number of words in database</td><td>%d</td></tr>" % len(self.db.words)
        html += "<tr><td>Number of words tested</td><td>%d</td></tr>" % number_of_words_tested
        html += "<tr><td>Number of words mastered</td><td>%d</td></tr>" % number_of_words_mastered 
        html += "<tr><td>Number of words yet to be mastered</td><td>%d</td></tr>" % (len(self.db.words) - number_of_words_mastered)
        html += "</table>"

        html += '<h3 bgcolor="rgb(200,200,200)">&nbsp;Words yet to be mastered by practice sets</h3>'
        html += '<table width="100%">'
        index_names = self.db.get_available_index_names()
        index_names.sort()
        for x in index_names:
            html += "<tr><td>%s</td><td>%d</td></tr>" % (x,len(self.db.get_indices(x)))
        html += "</table>"

        html += "</body></html>"

        return html

    def reveal_answer(self,feedback):
        if self.test_word == None: return
        output = '<h3>%s</h3>' % feedback
        output += self.get_word_html(self.test_word)
        self.main_frame.panel_output.output_box.setText(output)
        self.main_frame.panel_output.output_box.setCaretPosition(0)

    def update_labels(self):
        if self.test_word == None: return
        self.main_frame.panel_labels.lbl_test_word.setText(self.test_word.name)
        self.main_frame.panel_labels.lbl_practice_set.setText("Current Practice Set : " + self.active_index_name)
        self.main_frame.panel_labels.lbl_times_tested.setText("Number of times tested : " + self.test_word.stats['number_of_times_tested'])
        self.main_frame.panel_labels.lbl_words_mastered.setText(
            "%d of %d mastered (%.2f %%)" % (
                self.db.get_number_of_words_mastered(), 
                len(self.db.words), 
                self.db.get_number_of_words_mastered() / float(len(self.db.words)) * 100
            )
        )
    
    def open_dictionary(self):
        self.dframe = DictionaryFrame()
        self.dframe.setSize(500,300)
        self.dframe.setLocation(
            self.dframe.getToolkit().getScreenSize().width/2 - self.dframe.getWidth()/2,
            self.dframe.getToolkit().getScreenSize().height/2 - self.dframe.getHeight()/2
        )
        self.dframe.setTitle("Dictionary")
        list_model = DefaultListModel()
        for word in self.db.words:
            list_model.addElement(word.name)
        self.dframe.list_box.setModel(list_model)
        self.dframe.result_box.addHyperlinkListener(self.hyperlink_listener)
        self.dframe.list_box.addMouseListener(self.mouse_listener)
        self.dframe.txt_search.addKeyListener(self.keyboard_listener)
        self.dframe.cmd_search.addMouseListener(self.mouse_listener)
        self.dframe.setVisible(True)
        
    def mark_mastered(self, feedback):
        if self.test_word == None: return
        self.db.mark_mastered(self.test_word_index)
        self.update_labels()
        self.reveal_answer(feedback)

    def set_active_index_name(self, index_name):
        if self.active_index_name != index_name:
            self.active_index_name = index_name
            self.test()

    def test(self):
        help_html = "<h3>Make a guess by typing a choice number, or hit ESC to give up.</h3>"
        help_html += "<p><b>m</b> to mark current word as mastered. <b>d</b> to open dictionary.</p>"
        self.main_frame.panel_output.output_box.setText(help_html)
        (self.test_word_index, self.test_word) = self.__get_next_test_word()
        if self.test_word == None : return False
        trick_words = self.__get_trick_words(self.number_of_choices -1)
        self.update_labels()
        self.correct_choice = random.randint(1,self.number_of_choices)

        self.test_word.stats['number_of_times_tested'] = str(int(self.test_word.stats['number_of_times_tested']) + 1)
        trick_word_index = 0;
        choices = "<table>"
        for x in range(self.number_of_choices):
            choices += "<tr>"
            choices += '<td valign="top" width="20px"><b>%d</b>.<td>' % (x+1)
            if x != self.correct_choice-1:
                mindex = random.randint(0,len(trick_words[trick_word_index].meanings)-1)
                choices += '<td valign="top">' + trick_words[trick_word_index].meanings[mindex][0] + "</td>"
                trick_word_index += 1
            else:
                mindex = random.randint(0,len(self.test_word.meanings)-1)
                choices += "<td>" + self.test_word.meanings[mindex][0] + "</td>"
            choices += "</tr>"
        choices += "</table>"
        self.main_frame.panel_choices.choices_box.setText(choices)
        self.main_frame.panel_choices.choices_box.setCaretPosition(0)
        return True

    def save(self):
        try:
            self.db.write_db(".db.txt",".patterns_to_index.txt")
            return True
        except:
            return False
